package com.koron.standard.deviceClasssify.controller;


import cn.hutool.core.util.StrUtil;
import cn.hutool.poi.excel.WorkbookUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.enums.CellExtraTypeEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.koron.bean.base.Response;
import com.koron.common.core.util.EasyExcelUtils;
import com.koron.standard.bean.query.PageQuery;
import com.koron.standard.deviceClasssify.bean.dto.BaseTypeDTO;
import com.koron.standard.deviceClasssify.bean.dto.TypeDTO;
import com.koron.standard.deviceClasssify.bean.excel.TypeExcel;
import com.koron.standard.deviceClasssify.bean.excel.TypeParamsExcel;
import com.koron.standard.deviceClasssify.bean.po.Type;
import com.koron.standard.deviceClasssify.excel.TypeCodeCheckExcelListener;
import com.koron.standard.deviceClasssify.excel.TypeExcelListener;
import com.koron.standard.deviceClasssify.excel.TypeParamsExcelListener;
import com.koron.standard.deviceClasssify.service.StandardService;
import com.koron.standard.deviceClasssify.service.TypeParamsService;
import com.koron.standard.deviceClasssify.service.TypeService;
import com.koron.standard.excel.ErrorFillWriteHandler;
import com.koron.standard.excel.SameRowMargeStrategy;
import com.koron.standard.utils.StandardCodeTools;
import com.koron.standard.utils.TreeUtils;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiParam;
import lombok.SneakyThrows;
import org.apache.poi.ss.usermodel.Workbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.net.URLEncoder;
import java.util.*;

/**
 * 设备分类基本信息(Type表)控制层
 *
 * @author jzp
 * @since 2021-07-13 17:13:25
 */
@Api(tags = "设备分类基本信息接口")
@RestController
@RequestMapping("deviceClassify")
public class TypeController {

    @Autowired
    private TypeService typeService;
    @Autowired
    private TypeParamsService typeParamsService;

    @Autowired
    private StandardService standardService;

    @GetMapping("tree")
    @ApiOperation(value = "全加载设备分类树")
    public Response tree() {
        LambdaQueryWrapper<Type> wrapper = new LambdaQueryWrapper<>();
        wrapper.orderByAsc(Type::getSort);
        List<Type> list = typeService.list(wrapper);
        return Response.ok(TreeUtils.rootToTree(list, Type::getId, Type::getParentId));
    }

    @GetMapping
    @ApiOperation(value = "查询一条设备分类基本信息，包括设备分类信息和技术参数")
    public Response<TypeDTO> selectOne(@RequestParam String id) {
        TypeDTO typeDTO = typeService.getDtoById(id);
        return Response.ok(typeDTO);
    }

    @GetMapping("page")
    @ApiOperation(value = "分页查询", notes = "先根据id查询其所有子节点，再根据name筛选")
    public Response<Page<Type>> page(@RequestParam(required = false) String name, @RequestParam(required = false) String id, PageQuery<Type> pageQuery) {
        Type byId = typeService.getBaseMapper().selectById(id);
        LambdaQueryWrapper<Type> wrapper = new LambdaQueryWrapper<>();
        if (byId != null) {
            wrapper.likeRight(Type::getCode, byId.getCode());
        }
        wrapper.like(Type::getName, name);
        wrapper.orderByAsc(Type::getSort);
        Page<Type> page = pageQuery.convertPage();
        typeService.page(page, wrapper);
        return Response.ok(page);
    }

    @GetMapping("list")
    @ApiOperation(value = "list分类树", notes = "根据设备分类名模糊查询")
    public Response<List<Type>> list(String name) {
        LambdaQueryWrapper<Type> wrapper = new LambdaQueryWrapper<>();
        wrapper.like(Type::getName, name);
        wrapper.orderByAsc(Type::getSort);
        List<Type> list = typeService.list(wrapper);
        return Response.ok(list);
    }

    @GetMapping("node")
    @ApiOperation(value = "根据id查询其所有子节点")
    public Response node(@RequestParam(required = false) String id) {
        Type byId = typeService.getBaseMapper().selectById(id);
        LambdaQueryWrapper<Type> wrapper = new LambdaQueryWrapper<>();
        if (byId != null) {
            wrapper.likeRight(Type::getCode, byId.getCode());
        }
        wrapper.orderByAsc(Type::getSort);
        List<Type> list = typeService.list(wrapper);
        List<Type> singleton = Collections.singletonList(byId);
        return Response.ok(TreeUtils.rowsToTree(list, singleton, Type::getId, Type::getParentId, null));
    }

    @PostMapping("getRealByIds")
    @ApiOperation(value = "根据id批量查询分类")
    public Response getRealByIds(@RequestBody List<String> typeIds) {
        return Response.ok(typeService.getBaseMapper().getRealByIds(typeIds));
    }

    /**
     * 对分类标准进行过滤
     * 返回有相应标准的分类id集合
     *
     * @param typeIds 分类标准集合
     * @param refType 标准类型，字典：standard_ref_type
     * @return 有相应标准的分类id结婚
     */
    @PostMapping("filterStandard")
    @ApiOperation(value = "对分类标准进行过滤")
    public Response<List<String>> filterStandard(@RequestBody List<String> typeIds, @ApiParam("标准类型，字典：standard_ref_type") String refType) {
        return Response.ok(standardService.filterStandard(typeIds, refType));
    }

    /**
     *
     * @param id 设备分类id
     * @return
     * {
     *     设备分类基本信息
     *     技术参数 -> list:typeParamsList
     *     基本参数 -> list:typeGroupParamsList
     * }
     */
    @GetMapping("detail")
    @ApiOperation(value = "查询一条设备分类基本数据，包括设备分类信息、基本参数和技术参数")
    public Response<BaseTypeDTO> selectDetailOne(String id) {
        BaseTypeDTO typeDTO = typeService.getBaseDtoById(id);
        return Response.ok(typeDTO);
    }

    @PostMapping
    @ApiOperation(value = "新增或修改一条设备分类基本信息数据")
    public Response insert(@RequestBody TypeDTO typeDTO) {
        typeService.saveOrUpdateDto(typeDTO);
        return Response.ok(typeDTO.getId());
    }

    /**
     * 将c_type_params的表逗号分割的数据改为json格式
     */
    @PutMapping("fixParams")
    @ApiOperation(value = "修正技术参数中data_text逗号分割的数据")
    public Response fixParams() {
        typeService.fixParams();
        return Response.ok();
    }

    /**
     * 拖拽设备分类树节点
     * @param id 被拖拽节点的节点id
     * @param targetId 结束拖拽时最后进入的节点id
     * @param position 被拖拽节点的放置位置（before、after、inner）
     */
    @PutMapping("drag")
    @ApiOperation(value = "拖拽设备分类树节点")
    public Response drag(@RequestParam("id") @ApiParam("被拖拽节点的节点id") String id,
                         @RequestParam("targetId") @ApiParam("结束拖拽时最后进入的节点id") String targetId,
                         @RequestParam("position") @ApiParam("被拖拽节点的放置位置（before、after、inner）") String position) {
        typeService.drag(id, targetId, position);
        return Response.ok();
    }

    @DeleteMapping
    @ApiOperation(value = "删除一条设备分类基本信息数据")
    public Response<Type> delete(@RequestParam String id) {
        typeService.deleteDto(id);
        return Response.ok();
    }

    @SneakyThrows
    @ApiOperation(value = "下载模板")
    @GetMapping("template")
    public void template(HttpServletResponse response) {
        String path = "excel/device_type_standard.xlsx";
        ClassPathResource classPathResource = new ClassPathResource(path);
        Workbook book = WorkbookUtil.createBook(classPathResource.getInputStream());
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("分类标准", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        book.write(response.getOutputStream());
    }

    @SneakyThrows
    @ApiOperation(value = "导入")
    @PostMapping("import")
    public Response importFile(@RequestParam("file") MultipartFile file) {
        // 1. 检查分类编码是否重复
        TypeCodeCheckExcelListener typeCodeCheckExcelListener = new TypeCodeCheckExcelListener(typeService.listAllCode());
        EasyExcel.read(file.getInputStream(), TypeExcel.class, typeCodeCheckExcelListener)
                .extraRead(CellExtraTypeEnum.MERGE)
                .sheet("分类标准")
                .headRowNumber(2)
                .doRead();
        if (typeCodeCheckExcelListener.getExcelErrors().size() != 0) {
            // 输出错误文件
            String filename = StandardCodeTools.getFileCode();
            String tempPath = EasyExcelUtils.createTempFile(filename, "xlsx");
            EasyExcel.write(tempPath)
                    .inMemory(true)
                    .registerWriteHandler(new ErrorFillWriteHandler(typeCodeCheckExcelListener.getExcelErrors()))
                    .withTemplate(file.getInputStream())
                    .sheet("分类标准").doWrite(new ArrayList<>());
            return Response.ok("temp/" + filename + ".xlsx");
        }

        // 2. 分类标准数据导入
        EasyExcel.read(file.getInputStream(), TypeExcel.class, new TypeExcelListener(typeService, typeParamsService))
                .sheet("分类标准")
                .headRowNumber(2)
                .doRead();

        // 3. 技术参数导入
        TypeParamsExcelListener typeParamsExcelListener = new TypeParamsExcelListener(typeService, typeParamsService);
        EasyExcel.read(file.getInputStream(), TypeParamsExcel.class, typeParamsExcelListener)
                .sheet("技术参数")
                .headRowNumber(1)
                .doRead();
        if (typeParamsExcelListener.getExcelErrors().size() != 0) {
            // 输出错误文件
            String filename = StandardCodeTools.getFileCode();
            String tempPath = EasyExcelUtils.createTempFile(filename, "xlsx");
            EasyExcel.write(tempPath)
                    .inMemory(true)
                    .registerWriteHandler(new ErrorFillWriteHandler(typeParamsExcelListener.getExcelErrors()))
                    .withTemplate(file.getInputStream())
                    .sheet("技术参数").doWrite(new ArrayList<>());
            return Response.ok("temp/" + filename + ".xlsx");
        }
        return Response.ok("导入成功", null);
    }

    @SneakyThrows
    @ApiOperation(value = "导出", notes = "导出选中的节点树，id为空则导出所有")
    @GetMapping("export")
    public void exportFile(HttpServletResponse response, @RequestParam(required = false) String id) {
        String path = "excel/device_type_standard_export.xlsx";
        ClassPathResource classPathResource = new ClassPathResource(path);
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        String typeName = StrUtil.isEmpty(id) ? "分类标准" : typeService.getById(id).getName();
        typeName = StrUtil.isEmpty(typeName) ? "分类标准" : typeName;
        String fileName = URLEncoder.encode(typeName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        List<TypeExcel> typeExcelList = typeService.listTypeExcel(id);
        typeExcelList.sort(Comparator.comparing(TypeExcel::getCode));
        EasyExcel.write(response.getOutputStream())
                .withTemplate(classPathResource.getInputStream())
                .sheet("分类标准")
                .registerWriteHandler(new SameRowMargeStrategy<TypeExcel>(typeExcelList, new HashSet<>(Arrays.asList(0, 1, 2, 3, 4, 5)), TypeExcel::getCode))
                .doFill(typeExcelList);
    }
}
